/*
 * bsp_encoder_as5047p.c
 *
 *  Created on: 2025 Apr 8
 *      Author: SFLY
 */
#include "bsp_encoder_as5047p.h"


void GPIO_Config(uint32_t pin, GPIO_PinMux mux, GPIO_Direction dir, GPIO_PinType type,
    GPIO_QualificationMode qual)
{
    GPIO_setPinConfig(mux);
    GPIO_setDirectionMode(pin, dir);
    GPIO_setPadConfig(pin, type);
    /* output mode no need config qualification */
    if (dir == GPIO_DIR_MODE_IN)
        GPIO_setQualificationMode(pin, qual);
}


/*******************************************************************************
 * 函数名：Bsp_Encoder_Init
 * 描述  ：对电机端和减速器端编码器的SPI接口进行初始化配置。
 * 输入  ：无
 * 输出  ：无
 * 调用  ：内部调用
 * 备注  ：先对电机端和减速器端编码器的SPI接口GPIO进行定义和配置，
 *         之后使能相应的外设时钟，对SPI模块进行配置和使能，
 *         最后设置片选信号并进行短暂延时。
 *******************************************************************************/
void Bsp_Encoder_Init(void)
{
    //电机端编码器SPI接口GPIO定义
    GPIO_Config(GPIO_MOTOR_CLK, GPIO_CONFIG_MOTOR_CLK, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_MOTOR_CS, GPIO_CONFIG_GPIO_MOTOR_CS, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_MOTOR_MOSI, GPIO_CONFIG_GPIO_MOTOR_MOSI, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_MOTOR_MISO, GPIO_CONFIG_GPIO_MOTOR_MISO, GPIO_DIR_MODE_IN, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_writePin(GPIO_MOTOR_CS,SPI_CS_H);
    //减速器端编码器SPI接口GPIO定义
    GPIO_Config(GPIO_REDUCER_CLK, GPIO_CONFIG_REDUCER_CLK, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_REDUCER_CS, GPIO_CONFIG_GPIO_REDUCER_CS, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_REDUCER_MOSI, GPIO_CONFIG_GPIO_REDUCER_MOSI, GPIO_DIR_MODE_OUT, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_Config(GPIO_REDUCER_MISO, GPIO_CONFIG_GPIO_REDUCER_MISO, GPIO_DIR_MODE_IN, GPIO_PIN_TYPE_STD, GPIO_QUAL_ASYNC);
    GPIO_writePin(GPIO_REDUCER_CS,SPI_CS_H);

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIA);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SPIB);
    SPI_disableModule(SPI_MOTOR_BASE);
    SPI_setConfig(SPI_MOTOR_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, \
                SPI_MODE_CONTROLLER, SPI_FREQ, SPI_DATA_BITS_16);
    SPI_enableModule(SPI_MOTOR_BASE);

    SPI_disableModule(SPI_REDUCER_BASE);
    SPI_setConfig(SPI_REDUCER_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, \
                    SPI_MODE_CONTROLLER, SPI_FREQ, SPI_DATA_BITS_16);
    SPI_enableModule(SPI_REDUCER_BASE);
    SPI_MOTOR_CS_H
    SPI_REDUCER_CS_H
    DEVICE_DELAY_US(1000);
}


/*******************************************************************************
 * 函数名：parity_even
 * 描述  ：计算 16 位无符号整数的偶校验位。若该整数二进制表示中 1 的个数为偶数，返回 0；若为奇数，返回 1。
 * 输入  ：v，一个 16 位无符号整数
 * 输出  ：偶校验位，值为 0 或 1
 * 调用  ：内部调用
 * 备注  ：通过对输入的 16 位整数进行多次异或操作合并奇偶性信息，最终得出偶校验位。若输入为 0，直接返回 0。
 *******************************************************************************/
static uint8_t parity_even(uint16_t v)
{
    if(v == 0) return 0;
    v ^= v >> 8;
    v ^= v >> 4;
    v ^= v >> 2;
    v ^= v >> 1;
    return v & 1;
}

/*******************************************************************************
 * 函数名：Bsp_SendByte
 * 描述  ：SPI读取数据
 * 输入  ：spi_base_addr,data
 * 输出  ：Outdata
 * 调用  ：内部调用
 * 备注  ：通过发送一个字节的数据并同时接收一个字节的数据，实现了数据的读取操作。
 *******************************************************************************/
uint16_t Bsp_Encoder_SendByte(uint32_t base, uint16_t data)
{
    while(SPI_getTxFIFOStatus(base) != SPI_FIFO_TXEMPTY);
    SPI_writeDataBlockingFIFO(base, data);
    while(SPI_getRxFIFOStatus(base) != SPI_FIFO_RX1);
    return SPI_readDataBlockingFIFO(base);
}

//电机端编码器读写接口API
void BSP_Motor_Encoder_Write(uint16_t address,uint16_t value)
{
    if (parity_even(address & 0x3FFF) == 1) address = address | 0x8000; // set parity bit
       SPI_MOTOR_CS_L
       DEVICE_DELAY_US(1);
       Bsp_Encoder_SendByte(SPI_MOTOR_BASE,address);
       DEVICE_DELAY_US(1);
       SPI_MOTOR_CS_H
       DEVICE_DELAY_US(1);
       if (parity_even(value & 0x3FFF) == 1) value = value | 0x8000; // set parity bit
       SPI_MOTOR_CS_L
       DEVICE_DELAY_US(1);
       Bsp_Encoder_SendByte(SPI_MOTOR_BASE,value);
       DEVICE_DELAY_US(1);
       SPI_MOTOR_CS_H
}


uint16_t BSP_Motor_Encoder_Read(uint16_t address)
{
       uint16_t data = 0;
       if (parity_even(address | 0x4000) == 1) address = address | 0x8000; // set parity bit
           address = address | 0x4000; // it's a read command
           SPI_MOTOR_CS_L
           DEVICE_DELAY_US(1);
           Bsp_Encoder_SendByte(SPI_MOTOR_BASE,address);
           DEVICE_DELAY_US(1);
           SPI_MOTOR_CS_H
           DEVICE_DELAY_US(1);
           SPI_MOTOR_CS_L
           DEVICE_DELAY_US(1);
           data= Bsp_Encoder_SendByte(SPI_MOTOR_BASE,address);
           DEVICE_DELAY_US(1);
           SPI_MOTOR_CS_H
           data = data & 0x3FFF;  // filter bits outside data, strip bit 14..15
           return data;
}

uint16_t BSP_Motor_Encoder_ReadAngle(void)
{
    uint16_t data = 0;
    data =  BSP_Motor_Encoder_Read(ANGLECOM_ADDR);
    return data;
}

//减速器端编码器读写接口API
void BSP_Reducer_Encoder_Write(uint16_t address,uint16_t value)
{
    if (parity_even(address & 0x3FFF) == 1) address = address | 0x8000; // set parity bit
       SPI_REDUCER_CS_L
       DEVICE_DELAY_US(1);
       Bsp_Encoder_SendByte(SPI_REDUCER_BASE,address);
       DEVICE_DELAY_US(1);
       SPI_REDUCER_CS_H
       DEVICE_DELAY_US(1);
       if (parity_even(value & 0x3FFF) == 1) value = value | 0x8000; // set parity bit
       SPI_REDUCER_CS_L
       DEVICE_DELAY_US(1);
       Bsp_Encoder_SendByte(SPI_REDUCER_BASE,value);
       DEVICE_DELAY_US(1);
       SPI_REDUCER_CS_H
}

uint16_t BSP_Reducer_Encoder_Read(uint16_t address)
{
       uint16_t data = 0;
       if (parity_even(address | 0x4000) == 1) address = address | 0x8000; // set parity bit
           address = address | 0x4000; // it's a read command
           SPI_REDUCER_CS_L
           DEVICE_DELAY_US(1);
           Bsp_Encoder_SendByte(SPI_REDUCER_BASE,address);
           DEVICE_DELAY_US(1);
           SPI_REDUCER_CS_H
           DEVICE_DELAY_US(1);
           SPI_REDUCER_CS_L
           DEVICE_DELAY_US(1);
           data= Bsp_Encoder_SendByte(SPI_REDUCER_BASE,address);
           DEVICE_DELAY_US(1);
           SPI_REDUCER_CS_H
           data = data & 0x3FFF;  // filter bits outside data, strip bit 14..15
           return data;
}

uint16_t BSP_Reducer_Encoder_ReadAngle(void)
{
    uint16_t data = 0;
    data =  BSP_Reducer_Encoder_Read(ANGLECOM_ADDR);
    return data;
}



